/*
 *
 *  Copyright (C) 2012-2024
 *  All rights reserved, Designed By 杭州连线客信息技术有限公司
 *  注意：
 *  本软件为杭州连线客信息技术有限公司开发研制，未经购买不得使用
 *  购买后可获得全部源代码（禁止转卖、分享、上传到码云、github等开源平台）
 *  一经发现盗用、分享等行为，将追究法律责任，后果自负
 *
 */

package com.lxk.oms.flow.pay;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lxk.event.helper.EventHelper;
import com.lxk.event.oms.OrderOptionLogEvent;
import com.lxk.event.oms.OrderPaySuccessEvent;
import com.lxk.event.oms.enums.OrderEnums;
import com.lxk.oms.order.domain.vo.OmsOrderVo;
import com.lxk.oms.order.service.IOmsOrderService;
import com.lxk.service.core.Result;
import com.lxk.service.finance.api.WalletServiceApi;
import com.lxk.service.finance.enums.AccountTypeEnum;
import com.lxk.service.finance.request.QueryAccountParam;
import com.lxk.service.finance.request.UpdateAccountParam;
import com.lxk.service.finance.response.UserAccountDto;
import com.lxk.service.ums.response.UmsUserDto;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.FlowExecutor;
import com.yomahub.liteflow.core.NodeComponent;
import com.yomahub.liteflow.log.LFLog;
import com.yomahub.liteflow.log.LFLoggerManager;
import lombok.AllArgsConstructor;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.StreamUtils;

import java.math.BigDecimal;
import java.util.List;

/**
 * 积分支付节点
 *
 * @author heyi
 * 2024/8/22
 */
@LiteflowComponent(value = FlowPayOrderNodeConst.POINT_PAY)
@AllArgsConstructor
public class PointPayNode extends NodeComponent {
    private final WalletServiceApi walletServiceApi;
    private final IOmsOrderService omsOrderService;
    private final LFLog log = LFLoggerManager.getLogger(FlowExecutor.class);

    @Override
    public void beforeProcess() {
        PayContext contextBean = getContextBean(PayContext.class);
        List<OmsOrderVo> omsOrderList = contextBean.getOmsOrder();
        String orderSnList = StreamUtils.join(omsOrderList, OmsOrderVo::getOrderNo);
        BigDecimal totalPayPoint = omsOrderList.stream().map(OmsOrderVo::getPayPoint).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        QueryAccountParam accountParam = new QueryAccountParam().setUserId(contextBean.getUserId()).setAccountType(AccountTypeEnum.POINT.getCode());
        Result<UserAccountDto> result = walletServiceApi.queryByParam(accountParam);
        if (result.isFail()) {
            throw new ServiceException(result.getMsg());
        }
        UserAccountDto accountDto = result.getData();
        if (ObjectUtil.isNull(accountDto)) {
            log.error("账户异常,参数:{}", accountParam);
            throw new ServiceException("账户异常");
        }
        contextBean.setUserAccount(accountDto);
        BigDecimal amount = accountDto.getAmount();
        if (amount.compareTo(totalPayPoint) < 0) {
            log.error("您的积分不足,积分:{},订单支付积分:{},订单编号:{}", amount, totalPayPoint, orderSnList);
            if (CollUtil.size(omsOrderList) == 1) {
                sendPointNotEnoughEvent(contextBean, omsOrderList.get(0));
            }
            throw new ServiceException("您的积分不足,请充值");
        }

    }

    @Override
    public void process() throws Exception {
        PayContext contextBean = getContextBean(PayContext.class);
        UmsUserDto user = contextBean.getUser();
        List<OmsOrderVo> omsOrder = contextBean.getOmsOrder();
        omsOrder.forEach(order -> {
            UpdateAccountParam param = new UpdateAccountParam();
            param.setUserId(user.getUserId());
            param.setAccountType(contextBean.getUserAccount().getAccountType());
            param.setOrderSn(order.getOrderNo());
            param.setAmount(order.getPayPoint());
            param.setExtraInfo(StrUtil.format("积分支付订单:{}", order.getOrderNo()));
            Result<Boolean> reduce = walletServiceApi.reduce(param);
            if (!(reduce.isSuccess() && reduce.getData())) {
                sendPointNotEnoughEvent(contextBean, order);
                throw new ServiceException("您的积分不足");
            }
            // 订单已支付
            contextBean.setPayStatus(true);
        });
    }


    @Override
    public void onSuccess() throws Exception {
        PayContext contextBean = getContextBean(PayContext.class);
        contextBean.getOmsOrder().forEach(omsOrderVo -> {
            // 余额支付且支付成功了
            Boolean success = omsOrderService.paySuccess(omsOrderVo, null, OrderEnums.PayType.PONIT.getCode());
            if (!success) {
                throw new ServiceException("订单支付异常");
            }
            UmsUserDto umsUserDto = contextBean.getUser();
            Long userId = umsUserDto.getUserId();
            sendOrderOptionEvent(contextBean, omsOrderVo);
            OrderPaySuccessEvent successEvent = new OrderPaySuccessEvent();
            successEvent.setActPayPrice(omsOrderVo.getActPayPrice());
            successEvent.setUserId(userId);
            successEvent.setTenantId(contextBean.getTenantId());
            successEvent.setOrderType(omsOrderVo.getOrderType());
            successEvent.setOrderNo(omsOrderVo.getOrderNo());
            successEvent.setOrderId(omsOrderVo.getId());
            EventHelper.publishEvent(successEvent);
        });

    }

    private void sendOrderOptionEvent(PayContext contextBean, OmsOrderVo omsOrder) {
        UmsUserDto user = contextBean.getUser();
        OrderOptionLogEvent createEvent = new OrderOptionLogEvent();
        createEvent.setOrderSn(omsOrder.getOrderNo());
        createEvent.setUserId(user.getUserId());
        createEvent.setMerId(omsOrder.getMerId());
        createEvent.setTenantId(contextBean.getTenantId());
        createEvent.setOrderLogEnums(OrderOptionLogEvent.OrderLogEnums.ORDER);
        createEvent.setUserType(user.getUserType());
        createEvent.setContent(
            OrderOptionLogEvent.OrderContentFormatEnums.PAY_SUCCESS_ORDER.formatContent(user.getNickName(),
                omsOrder.getOrderNo(),
                OrderEnums.PayType.getByCode(contextBean.getPayType()).getName())
        );
        EventHelper.publishEvent(createEvent);
    }

    private void sendPointNotEnoughEvent(PayContext contextBean, OmsOrderVo omsOrder) {
        UmsUserDto user = contextBean.getUser();
        UserAccountDto userAccount = contextBean.getUserAccount();
        OrderOptionLogEvent createEvent = new OrderOptionLogEvent();
        createEvent.setOrderSn(omsOrder.getOrderNo());
        createEvent.setUserId(user.getUserId());
        createEvent.setMerId(omsOrder.getMerId());
        createEvent.setTenantId(contextBean.getTenantId());
        createEvent.setOrderLogEnums(OrderOptionLogEvent.OrderLogEnums.ORDER);
        createEvent.setUserType(user.getUserType());
        createEvent.setContent(
            OrderOptionLogEvent.OrderContentFormatEnums.POINT_NOT_ENOUGH.formatContent(user.getNickName(),
                userAccount.getAmount().toString(),
                omsOrder.getPayPoint().toString()
            )
        );
        EventHelper.publishEvent(createEvent);
    }

}
